"""
The MIT License (MIT)
Copyright © 2022 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-drivers

# IMPORTANT: THIS MODULE ONLY TESTED ON ESP32 BOARD
"""
from machine import TouchPad as TP, Pin, Timer

VALID_PINS = [0, 2, 4, 12, 13, 14, 15, 27, 32, 33]


class TouchPadException(BaseException):
	pass


class TouchPad(object):
	__MAX_VALUE = 100 # 按键按下后的读数最大值，大于这个值则认为按键未按下

	def __init__(self, pins, touch_cb=None, timer_id=10, valid_pins=VALID_PINS):
		assert pins is not None, TouchPadException('pin must be specified')
		assert isinstance(pins, (int, list, tuple)), TouchPadException('invalid pin format')
		assert touch_cb is not None, TouchPadException('touch_cb must be specified')
		assert isinstance(valid_pins, (int, list, tuple)), TouchPadException('invalid valid_pins format')

		self.__key_list = [] # 保存 TouchPad 实例
		self.__pin_list = [] # 保存 TouchPad 使用的 io
		self.__last_status = [] # 记录按键当前状态
		self.__touch_cb = touch_cb
		self.__paused = False # 暂停定时器任务
		self.__max_value = self.__MAX_VALUE

		if isinstance(pins, (list, tuple)):
			for _ in pins:
				self.__key_list.append(TP(Pin(_)))
				self.__pin_list.append(_)
				self.__last_status.append(False)
		else:
			self.__key_list.append(TP(Pin(pins)))
			self.__pin_list.append(pins)
			self.__last_status.append(False)

		if timer_id is not None:
			self.__timer = Timer(timer_id)

			self.__timer.init(
				mode=Timer.PERIODIC,
				period=20,
				callback=self.check_status
			)

	def deinit(self):
		self.__key_list = []
		self.__pin_list = []
		self.__last_status = []
		self.__touch_cb = None

		if self.__timer is not None:
			self.__timer.deinit()
			self.__timer = None

	def check_status(self, timer=None):
		'''
		定时器任务
		'''
		if self.__paused: return

		try:
			for index, key in enumerate(self.__key_list):
				touched = key.read() <= self.__max_value
				if self.__last_status[index] != touched:
					self.__last_status[index] = touched

					if self.__touch_cb:
						self.__touch_cb(self.__pin_list[index], touched)
		except ValueError:
			pass

	def is_touched(self, pin):
		if pin in self.__pin_list:
			return self.__last_status[self.__pin_list.index(pin)]
		else:
			print('invalide pin, return False')
			return False

	def add_key(self, pin):
		if self.is_validate_pin(pin) and pin not in self.__pin_list:
			self.__paused = True

			self.__key_list.append(TouchPad(Pin(pin)))
			self.__pin_list.append(pin)
			self.__last_status.append(False)

			self.__paused = False

	def del_key(self, pin):
		if pin in self.__pin_list:
			self.__paused = True

			index = self.__pin_list.index(pin)
			self.__pin_list.pop(index)
			self.__key_list.pop(index)
			self.__last_status.pop(index)

			self.__paused = False

	@property
	def max_value(self):
		return self.__max_value
	
	@max_value.setter
	def max_value(self, value):
		if isinstance(value, int):
			self.__max_value = value

	@staticmethod
	def is_validate_pin(pin):
		if pin in VALID_PINS:
			return True
		else:
			print(f'invalid pin ({pin}), ignored')
			return False


def run_test():
	touch_pin = 15
	__led = Pin(2, Pin.OUT, value=0)

	def touch_cb(pin, touched):
		print(f'key {pin} {"holding" if touched else "released"}')

		if pin == touch_pin:
			__led.value(touched)

	VALID_PINS = [0, 2, 4, 12, 13, 14, 15, 27, 32, 33]
	print(f'touch_pin {touch_pin} validation: {TouchPad.is_validate_pin(touch_pin)}')
	touchpad = TouchPad(touch_pin, touch_cb, valid_pins=VALID_PINS)
	touchpad.max_value = 100


if __name__ == '__main__':
	run_test()
